package com.oswift.gpm.service.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpSession;

import com.oswift.gpm.dao.LoginDao;
import com.oswift.gpm.dao.UserDao;
import com.oswift.gpm.entity.LoginBean;
import com.oswift.gpm.entity.MenuBean;
import com.oswift.gpm.entity.MessageBean;
import com.oswift.gpm.entity.SystemModuleBean;
import com.oswift.gpm.entity.UserBean;
import com.oswift.gpm.service.ILoginService;
import com.oswift.gpm.system.cache.LoginManager;
import com.oswift.gpm.utils.Constant;
import com.oswift.gpm.utils.PageCode;
import com.oswift.utils.cache.CacheAccessException;
import com.oswift.utils.cache.ResourceManager;
import com.oswift.utils.common.CipherUtil;
import com.oswift.utils.common.StringUtil;
import com.oswift.utils.common.TimeUtil;
import com.oswift.utils.exception.PlatException;

public class LoginServiceImpl implements ILoginService
{
    /**
     * LoginDao spring注入实例
     */
    private LoginDao loginDao;

    /**
     * UserDao spring注入实例
     */
    private UserDao userDao;

    /**
     *
     * 登录
     *
     * @author zhuou
     * @param userName
     *            用户名
     * @param password
     *            密码
     * @param lastLoginIP
     *            客户端IP
     * @return MessageBean
     * @throws PlatException
     *             公共异常
     */
    public MessageBean login(String userName, String password,
            String lastLoginIP, HttpSession session) throws PlatException
    {
        // 返回action信息
        MessageBean messBean = new MessageBean();

        // 获取当前时间
        Date nowDate = new Date();

        // 根据userName查询
        UserBean bean = loginDao.getUserByName(userName);
        if (null == bean)
        {
            messBean.setCode(PageCode.USER_NAMEORPASSWORD_ERROR);
            messBean.setContent(ResourceManager
                    .getValue(PageCode.USER_NAMEORPASSWORD_ERROR));
            return messBean;
        }

        // 是否容许多人同时登录
        if (!bean.isEnableMultiLogin())
        {
            boolean isExist = LoginManager.isUserExist(userName);
            if (isExist)
            {
                messBean.setCode(PageCode.ACCOUNT_ALREADY_LOAD);
                messBean.setContent(ResourceManager
                        .getValue(PageCode.ACCOUNT_ALREADY_LOAD));
                return messBean;
            }
        }

        boolean isOk = CipherUtil
                .validatePassword(bean.getPassword(), password);

        // 密码错误
        if (!isOk)
        {
            messBean.setCode(PageCode.USER_NAMEORPASSWORD_ERROR);
            messBean.setContent(ResourceManager
                    .getValue(PageCode.USER_NAMEORPASSWORD_ERROR));

            bean.setLastLoginIP(lastLoginIP);
            bean.setLastLoginTime(nowDate);
            int errorCount = bean.getLoginErrorCount() + 1;

            // 登录错误次数
            bean.setLoginErrorCount(errorCount);
            loginDao.updateUserLoginInfo(bean);

            // 判断是否用户有错误登录次数限制，0为不限制
            if (bean.getLoginErrorTime() > 0
                    && errorCount >= bean.getLoginErrorTime())
            {
                bean.setStatus(Constant.UserStatus.OVERTIME_LOCKED);
                // 锁定用户
                loginDao.updateStatus(Constant.UserStatus.OVERTIME_LOCKED, bean
                        .getUserId());
            }
            return messBean;
        }

        // 判断账户的有效期
        if (!StringUtil.isEmpty(bean.getAccountExpires()))
        {
            // 加一天，如2013-07-24 00:00:00，其实是2013-07-25 00:00:00结束
            Date accountExpire = TimeUtil.stringToDate(
                    bean.getAccountExpires(), TimeUtil.ISO_DATE_FORMAT);
            Calendar cal = Calendar.getInstance();
            cal.setTime(accountExpire);
            cal.add(Calendar.DAY_OF_YEAR, 1);

            if (cal.getTime().getTime() - nowDate.getTime() <= 0)
            {
                messBean.setCode(PageCode.ACCOUNT_OVERTIME);
                messBean.setContent(ResourceManager
                        .getValue(PageCode.ACCOUNT_OVERTIME));
                return messBean;
            }
        }

        // 判断用户是否和某个系统绑定
        List<SystemModuleBean> sysBeans = userDao.getSysByUserId(String
                .valueOf(bean.getUserId()));
        if (null == sysBeans || sysBeans.isEmpty())
        {
            messBean.setCode(PageCode.USER_NO_SYS);
            messBean.setContent(ResourceManager.getValue(PageCode.USER_NO_SYS));
            return messBean;
        }

        // 用户状态 是否被管理员锁定
        if (bean.getStatus() == Constant.UserStatus.ADMIN_LOCKED)
        {
            messBean.setCode(PageCode.USER_ADMIN_LOCKED);
            messBean.setContent(ResourceManager
                    .getValue(PageCode.USER_ADMIN_LOCKED));
            return messBean;
        }

        // 是否因为登录错误次数过多被锁定，被永久锁定情況
        if (bean.getStatus() == Constant.UserStatus.OVERTIME_LOCKED
                && bean.getLockTime() == 0)
        {
            messBean.setCode(PageCode.USER_OVERTIME_LOCKED_FOREVER);
            messBean.setContent(ResourceManager.getValue(
                    PageCode.USER_OVERTIME_LOCKED_FOREVER).replace("{0}",
                    String.valueOf(bean.getLoginErrorTime())));
            return messBean;
        }

        // 被锁定一定时间
        if (bean.getStatus() == Constant.UserStatus.OVERTIME_LOCKED
                && bean.getLockTime() > 0)
        {
            int iMinute = 0;
            // 获取最近登录时间
            if (null != bean.getLastLoginTime())
            {
                Date lastLoginDate = TimeUtil.stringToDate(bean
                        .getLastLoginTime(), TimeUtil.ISO_DATE_TIME_FORMAT);
                Long between = (nowDate.getTime() - lastLoginDate.getTime()) / 1000;

                // 计算出相差多少分钟
                between = between % 3600 / 60;

                // 转换为int类型
                iMinute = between.intValue();
            }

            // 设置的锁定时长和当前已经被锁定的时长比较
            if (bean.getLockTime() > iMinute)
            {
                messBean.setCode(PageCode.USER_OVERTIME_LOCKED);
                messBean.setContent(ResourceManager.getValue(
                        PageCode.USER_OVERTIME_LOCKED).replace("{0}",
                        String.valueOf(bean.getLockTime())));

                return messBean;
            }
            else
            {
                bean.setLoginErrorCount(0);
                // 解除锁定
                loginDao.updateStatus(Constant.UserStatus.NORMAL, bean
                        .getUserId());
            }
        }

        bean.setLastLoginIP(lastLoginIP);
        bean.setLastLoginTime(nowDate);

        // 更新登录信息
        loginDao.updateUserLoginInfo(bean);

        if (sysBeans.size() == 1)
        {
            // 将登录信息缓存起来
            setCacheLoginBean(bean, sysBeans.get(0));

            // 将systemId+userId的hash值放入session中
            StringBuilder sb = new StringBuilder();
            sb.append(sysBeans.get(0).getSystemId());
            sb.append(bean.getUserId());
            session
                    .setAttribute(Constant.SESSION_KEY, sb.toString()
                            .hashCode());

            // 登录成功
            messBean.setCode(PageCode.COMMON_SUCCESS);
        }
        else
        {
            // 由于用户属于多个系统，此时要跳转到系统选择页面，所有此时session存储登录用户Bean
            session.setAttribute(Constant.SESSION_KEY, bean);
            messBean.setCode(PageCode.USER_MULTIPLE_SYS);
        }

        return messBean;
    }

    /**
     *
     * 修改密码
     *
     * @author zhuou
     * @param userId
     *            后台用户id
     * @param pwd
     *            新密码
     * @return MessageBean
     */
    public MessageBean updatePWD(int userId, String oldPwd, String newPwd)
        throws PlatException
    {
        // 返回action信息
        MessageBean messBean = new MessageBean();

        UserBean userBean = userDao.selectOne(userId);
        if (null == userBean)
        {
            messBean.setCode(PageCode.LOGIN_USER_ISNOT_EXIST);
            messBean.setContent(ResourceManager
                    .getValue(PageCode.LOGIN_USER_ISNOT_EXIST));
            return messBean;
        }

        // 判断原密码是否正确
        boolean isOk = CipherUtil.validatePassword(userBean.getPassword(),
                oldPwd);
        if (!isOk)
        {
            messBean.setCode(PageCode.LOGIN_PASSWORD_NOT_RIGHT);
            messBean.setContent(ResourceManager
                    .getValue(PageCode.LOGIN_PASSWORD_NOT_RIGHT));
            return messBean;
        }

        // 是否容许修改密码
        if (!userBean.isEnableModifyPassword())
        {
            messBean.setCode(PageCode.LOGIN_PASSWORD_NOT_UPDATE);
            messBean.setContent(ResourceManager
                    .getValue(PageCode.LOGIN_PASSWORD_NOT_UPDATE));
            return messBean;
        }

        boolean isSuccess = loginDao.updatePassword(userId, CipherUtil
                .generatePassword(newPwd)) > 0 ? true : false;
        if (isSuccess)
        {
            messBean.setCode(PageCode.COMMON_SUCCESS);
            messBean.setContent(ResourceManager
                    .getValue(PageCode.LOGIN_PASSWORD_UPDATE_SUCCESS));
        }
        else
        {
            messBean.setCode(PageCode.LOGIN_PASSWORD_UPDATE_FAIL);
            messBean.setContent(ResourceManager
                    .getValue(PageCode.LOGIN_PASSWORD_UPDATE_FAIL));
        }
        return messBean;
    }

    /**
     *
     * 设置登录信息缓存
     *
     * @author zhuou
     * @param userBean
     *            用户信息
     * @param sysBean
     *            系统信息
     * @throws CacheAccessException
     *             缓存异常
     */
    public void setCacheLoginBean(UserBean userBean, SystemModuleBean sysBean)
        throws CacheAccessException
    {
        LoginBean loginBean = new LoginBean();
        StringBuilder sb = new StringBuilder();
        sb.append(sysBean.getSystemId());
        sb.append(userBean.getUserId());

        // systemId+userId的hash值
        long hashId = sb.toString().hashCode();

        loginBean.setHashId(hashId);
        loginBean.setSystemId(sysBean.getSystemId());
        loginBean.setSystemName(sysBean.getSystemName());
        loginBean.setSystemIP(sysBean.getSystemIP());
        loginBean.setSigned(sysBean.getSigned());
        loginBean.setUserId(userBean.getUserId());
        loginBean.setUserName(userBean.getUserName());
        loginBean.setHostAddr(sysBean.getHostAddr());

        LoginManager.setLoginBean(loginBean);
    }

    /**
     *
     * 根据userId、systemId和节点深度获取菜单列表
     *
     * @author zhuou
     * @param userId
     *            用户Id
     * @param systemId
     *            系统Id
     * @param noteLevel
     *            节点深度 如1只查节点深度为1 如1,2 只查节点深度为1,2的节点；当为空或者null查询全部
     * @param parentId
     *            父节点ID
     *
     * @return List
     * @throws PlatException
     *             公共异常
     */
    public List<MenuBean> getMenu(int userId, int systemId, int parentId,
            String noteLevel) throws PlatException
    {
        return loginDao.getMenu(userId, systemId, parentId, noteLevel);
    }

    /**
     *
     * 根据userId、systemId和url获取操作，可能有多个
     *
     * @author zhuou
     * @param userId
     *            用户Id
     * @param systemId
     *            系统Id
     * @param opsUrl
     *            操作Url
     * @return List
     * @throws PlatException
     *             公共异常
     */
    public List<MenuBean> getMenu(int userId, int systemId, String opsUrl)
        throws PlatException
    {
        return loginDao.getMenu(userId, systemId, opsUrl);
    }

    /**
     *
     * 根据userId、systemId和opsId获取某个操作
     *
     * @author zhuou
     * @param userId
     *            用户Id
     * @param systemId
     *            系统Id
     * @param opsId
     *            操作Id
     * @return MenuBean
     * @throws PlatException
     *             公共异常
     */
    public MenuBean getMenu(int userId, int systemId, int opsId)
        throws PlatException
    {
        return loginDao.getMenu(userId, systemId, opsId);
    }

    public LoginDao getLoginDao()
    {
        return loginDao;
    }

    public void setLoginDao(LoginDao loginDao)
    {
        this.loginDao = loginDao;
    }

    public UserDao getUserDao()
    {
        return userDao;
    }

    public void setUserDao(UserDao userDao)
    {
        this.userDao = userDao;
    }
}
